package sk.naive.talker.server;

import sk.naive.talker.*;
import sk.naive.talker.props.PropertyStoreException;
import sk.naive.talker.persistence.*;
import sk.naive.talker.util.Utils;

import java.util.*;
import java.rmi.RemoteException;

/**
 * @author <a href="mailto:rytier@naive.deepblue.sk">Martin "Rytier" Kerni</a>
 * @version $Revision: 1.17 $ $Date: 2005/02/20 13:08:17 $
 */
public class LocationRegistry extends PersistentObjectFactory implements LocationFinder {
	private Map<String, Location> nameLocation;
	private Map<Integer, Location> idLocation;

	private Set<String> locationNames;
	private Map<User, Location> userLocation;
	private Talker talker;

	public LocationRegistry(String propertiesBundleName, Set<String> locationNames, Talker talker) throws PersistenceException {
		super(propertiesBundleName);
		this.talker = talker;
		nameLocation = new HashMap<String, Location>();
		idLocation = new HashMap<Integer, Location>();
		this.locationNames = locationNames;
		userLocation = new HashMap<User, Location>();
		for (String locationName : locationNames) {
			Location location = getLocation(locationName);
			addLocation(location);
		}
		for (Location location : locations()) {
			location.init();
		}
	}

	public Location getLocation(String name) throws PersistenceException {
		return (Location) getPersistentObjectByName(name);
	}

	protected PersistentObject persistentObjectInstance(Integer id) throws PersistenceException {
		return new Location(id, this);
	}

	protected int getType() {
		return DbLayer.OBJECT_TYPE_LOCATION;
	}

	protected String getNamingProperty() {
		return Location.LPROP_NAME;
	}

	public LocationFinder finder() {
		return this;
	}

	public Location createLocation(String name) throws PersistenceException {
		name = Utils.normalize(name);
		Location loc = null;
		if (!locationNames.contains(name)) {
			loc = (Location) create(name);
			addLocation(loc);
		}
		return loc;
	}

	public void destroy(Location loc) throws PersistenceException, PropertyStoreException, RemoteException {
		removeLinksFromOtherLocations(loc);
		getUsersFromLocation(loc);
		remove(loc);
		removeLocation(loc);
	}

	public void rename(Location loc, String newName) throws PropertyStoreException {
		String oldName = loc.getName();
		loc.set(Location.LPROP_NAME, newName);
		locationNames.remove(oldName);
		locationNames.add(newName);
		nameLocation.remove(oldName);
		nameLocation.put(newName, loc);

	}

	private void getUsersFromLocation(Location loc) throws RemoteException {
		for (Iterator i = loc.users().iterator(); i.hasNext();) {
			User u = (User) i.next();
			u.send(talker.messageFactory().getString("server.currentLocationDestroyed", u.getProperties()));
			i.remove();
			loc.userOut(u);
		}
	}

	private void removeLinksFromOtherLocations(Location loc) throws PersistenceException, PropertyStoreException, RemoteException {
		for (Object o : locations()) {
			Location otherLoc = (Location) o;
			otherLoc.removeExit(loc);
		}
	}

	private void removeLocation(Location loc) {
		locationNames.remove(loc.getName());
		nameLocation.remove(loc.getName());
		idLocation.remove(loc.getId());
	}

	private void addLocation(Location loc) {
		locationNames.add(loc.getName());
		nameLocation.put(loc.getName(), loc);
		idLocation.put(loc.getId(), loc);
	}

	public Location findLocationById(Integer id) {
		return idLocation.get(id);
	}

	public Location findLocationByName(String name) {
		name = Utils.normalize(name);
		String foundName = Utils.findFirstInCollection(name, locationNames, false);
		if (foundName == null) {
			return null;
		}
		return nameLocation.get(foundName);
	}

	public Location findLocationForUser(User user) {
		return userLocation.get(user);
	}

	public void userToLocation(User user, Location loc) {
		if (loc != null) {
			userLocation.put(user, loc);
		} else {
			userLocation.remove(user);
		}
	}

	public Collection<Location> locations() {
		return idLocation.values();
	}

	public Collection<String> locationNames() {
		return locationNames;
	}
}
